package bma.common.langutil.core;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 
 * @author guanzhong
 * 
 * @param <K>
 * @param <V>
 */
public class MapWrap<K, V> implements Map<K, V>, Cloneable,
		java.io.Serializable {

	private static final long serialVersionUID = 1L;

	private Map<K, V> map;

	/**
	 * <p>
	 * Create a MapWrap that 'wraps' a <code>HashMap</code>.
	 * </p>
	 * 
	 * @see java.util.HashMap
	 */
	public MapWrap() {
		map = new HashMap<K, V>();
	}

	/**
	 * <p>
	 * Create a MapWrap that 'wraps' a <code>HashMap</code> that has the given
	 * initial capacity.
	 * </p>
	 * 
	 * @see java.util.HashMap
	 */
	public MapWrap(final int initialCapacity) {
		map = new HashMap<K, V>(initialCapacity);
	}

	/**
	 * <p>
	 * Create a MapWrap that 'wraps' a <code>HashMap</code> that has the given
	 * initial capacity and load factor.
	 * </p>
	 * 
	 * @see java.util.HashMap
	 */
	public MapWrap(final int initialCapacity, final float loadFactor) {
		map = new HashMap<K, V>(initialCapacity, loadFactor);
	}

	public MapWrap(Map<K, V> map) {
		super();
		this.map = map;
	}

	/**
	 * <p>
	 * Get a direct handle to the underlying Map.
	 * </p>
	 */
	public Map<K, V> getWrappedMap() {
		return map;
	}

	public void clear() {
		map.clear();
	}

	public boolean containsKey(final Object key) {
		return map.containsKey(key);
	}

	public boolean containsValue(final Object val) {
		return map.containsValue(val);
	}

	public Set<Entry<K, V>> entrySet() {
		return map.entrySet();
	}

	@Override
	public boolean equals(final Object obj) {
		if (obj == null || !(obj instanceof MapWrap)) {
			return false;
		}

		return map.equals(((MapWrap<?, ?>) obj).getWrappedMap());
	}

	@Override
	public int hashCode() {
		return map.hashCode();
	}

	public V get(final Object key) {
		return map.get(key);
	}

	public boolean isEmpty() {
		return map.isEmpty();
	}

	public Set<K> keySet() {
		return map.keySet();
	}

	public V put(final K key, final V val) {
		return map.put(key, val);
	}

	public void putAll(final Map<? extends K, ? extends V> t) {
		map.putAll(t);
	}

	public V remove(final Object key) {
		return map.remove(key);
	}

	public int size() {
		return map.size();
	}

	public Collection<V> values() {
		return map.values();
	}

	@Override
	@SuppressWarnings("unchecked")
	public Object clone() {
		MapWrap<K, V> copy;
		try {
			copy = (MapWrap<K, V>) super.clone();
			if (map instanceof HashMap) {
				copy.map = (Map<K, V>) ((HashMap<K, V>) map).clone();
			}
		} catch (CloneNotSupportedException ex) {
			throw new IncompatibleClassChangeError("Not Cloneable.");
		}

		return copy;
	}

}
